'''DataK Connection.

The Connection is the start point for DataK data access.
It defines the server location and the user login, as well as
the protocols used for data manipulations.

# LICENSE ....................................................................
    This file is part of DataK.

    DataK is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DataK is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DataK.  If not, see <http://www.gnu.org/licenses/>.
# ............................................................................

'''

from singleton import ClassKeySingleton as _ClassKeySingleton
import protocol

class ConnectionError( ValueError ):
    pass

#
#--- Connection
#
class Connection( _ClassKeySingleton ):
    '''
    The Connection is the start point for DataK data access.
    It defines the server location and the user login, as well as
    the protocols used for data manipulations.
    '''
    def __init__( self, id, user ):
        '''
        Create a connection on the id 'id' (path to the server)
        
        '''
        _ClassKeySingleton.__init__( self, )
        
        if not os.path.isdir(id):
            raise ConnectionError("Bad connection id: "+id)
            
        self.id = id
        self.user = user
        
        # TODO: use the protocol_config attribute
        # self._protocol = protocol.create_protocol(
        #    user, self._AsItem().protocol_config
        # )
        self._prorocol = protocol.create_protocol( user, None )
               
        self._asItem = None
    
    def set_protocol_option( self, optName, optVal, saveAsDefault=True ):
        '''
        Set an option of the connection protocol.
        
        The protocol may or may not use it.
        Use get_protocol_infos() for infos on usefull options.
        
        If saveAsDefault is True, further connections will have the
        option set by default.
        '''
        self._protocol.set_option( optName, optVal )
        if saveAsDefault:
            # TODO: save the protocol config in the protocol_config attribute
            # self._AsItem().protocol_config = protocol.get_definition(
            #    self._protocol
            # )
            pass
        
    def get_protocol_infos( self ):
        return self._protocol.__class__.__doc__
        
    def setup_item( self, item ):
        self._protocol.setup_item( item )
        
    def IsItem( self, id ):
        '''
        Return True if the given id exists under this connection.
        '''
        path = os.path.normpath( os.path.join( self.id, id.strip('/') ) )
        # I also check startswith to avoid ../../somewhere/else
        return (
            path.startswith( self.id ) 
            and (
                os.path.isdir( path )
                #or 
                #os.path.islink( path ) not needed since a link to a dir isdir.
            )
        )
    
    def GetPath( self ):
        '''
        Return the path of the connection in the filesystem.
        '''
        return self.id
    
    def GetPathFromId( self, id ):
        '''
        Return the path of the item with id 'id' on the filesystem.
        '''
        return os.path.join( self.id, id.strip('/') ) 
    
    def GetItem(self, id ):
        '''
        Get the item with the id 'id' under this connection.
        '''
        if not self.IsItem( id ):
            raise ConnectionError("Under "+self.id+", Bad Id: "+id)
        path = self.GetPathFromId( id )
        if os.path.islink( path ):
            trg = os.path.normpath( os.readlink(path) )
            if not trg.startswith( self.id ):
                #raise ConnectionError(
                #    "Link is pointing to Item outside connection:\n"
                #    +id+' -> '+trg
                #)
                pass
            return Link( self, id, trg[len(self.id):] )
        return Item( self, id )
            
    def _AsItem(self):
        '''
        Return an item representing the connection (empty id).
        A connection is not an item but sometime act like one
        using this method.
        '''
        if self._asItem is None:
            self._asItem = Item( self, '' )
        return self._asItem

    def __iter__( self ):
        '''
        => for i in connection:
               print i.name
        '''
        return iter( self._AsItem() )

    def __getitem__( self, select ):
        '''
        =>  connection[:3]
            connection['LIB']
            connection[:]
            etc... see Item.__getitem__
        '''
        return self._AsItem()[select]




